package net.wnb.mineclearance.ui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Stroke;
import java.io.IOException;

import net.wnb.mineclearance.model.Game;
import net.wnb.mineclearance.model.GameStateListener;

import wnb.util.io.FileSource;
import wnb.util.io.ImageManager;
import wnb.util.io.Terminal;
import wnb.util.ui.Animation;


public class GameAnimation implements Animation, GameStateListener{
	private static final String MINE_IMAGE_FILE_NAME = "res/images/mine.png";
	private static final float DEFAULT_LINE_WIDTH = 3.0f;
	private static final Color BORDER_COLOR = new Color(191, 191, 191);
	private static final Color PLAIN_COLOR = new Color(144, 238, 144);
	private static final int SECONDS_FOR_SHOWING_MESSAGE = 50;
	private Game game;
	private int state;
	private int secondsLeft;
	private int currentRow = -1;
	private int currentCol = -1;
	
	public GameAnimation(Game game){
		this.game = game;
		this.state = Game.STATE_PROCESSING;
		game.addGameStateListener(this);
	}

	@Override
	public void paintFrame(Graphics2D g2, int width, int height, int frameIndex) {
		g2.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
		int rowCount = game.getRowCount();
		int colCount = game.getColCount();
		
		try{
			for(int i=0;i<rowCount;i++){
				for(int j=0;j<colCount;j++){
					drawBackground(g2, width, height, i, j);
					
					boolean mask = game.getMaskAt(i, j);
					if(mask){
						int count = game.calcCount(i, j);
						if(count == -1){
							drawMine(g2, width, height, i, j);
						}else if(count > 0){
							drawNum(g2, width, height,  i, j, count);
						}
					}else{
						drawPlain(g2, width, height,  i, j);
					}
				}
			}
		}catch(IOException ex){
			Terminal.writeLine(ex.getMessage());
			ex.printStackTrace();
		}
		
		drawStateMessage(g2, width, height);
		drawCurrentGrid(g2, width, height);
	}

	private void drawCurrentGrid(Graphics2D g2, int width, int height) {
		if(currentCol < 0 || currentRow < 0)
			return;
		
		Dimension size = getGridSize(width, height);
		g2.setColor(Color.ORANGE);
		g2.drawRect(currentCol * size.width, currentRow * size.height, size.width, size.height);
	}

	private void drawStateMessage(Graphics2D g2, int width, int height) {
		if(secondsLeft < 0)
			return;
		
		switch(state){
		case Game.STATE_PROCESSING:
			break;
			
		case Game.STATE_SUCCESSED:
			drawMessage(g2, width, height, "恭喜您，挑战成功！", Color.GREEN, secondsLeft);
			secondsLeft--;
			break;
			
		case Game.STATE_FAILED:
			drawMessage(g2, width, height, "很遗憾，您战败了", Color.RED, secondsLeft);
			secondsLeft--;
			break;
		}
	}

	private void drawMessage(Graphics2D g2, int width, int height, String string, Color color, int secondsLeft) {
		FontMetrics metrics = g2.getFontMetrics();
		int w = metrics.stringWidth(string);
		int h = metrics.getHeight();
		int x = (width - w)/2;
		int y = h + 32;
		
		Color drawColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), 255 * secondsLeft / SECONDS_FOR_SHOWING_MESSAGE);
		g2.setColor(drawColor);
		g2.drawString(string, x, y);
	}

	private void drawPlain(Graphics2D g2, int width, int height, int rowIndex, int colIndex) {
		Dimension size = getGridSize(width, height);
		g2.setPaint(PLAIN_COLOR);
		g2.fillRect(
				colIndex * size.width + (int)DEFAULT_LINE_WIDTH, rowIndex * size.height + (int)DEFAULT_LINE_WIDTH, 
				size.width - (int)DEFAULT_LINE_WIDTH, 
				size.height - (int)DEFAULT_LINE_WIDTH
		);
	}

	private void drawNum(Graphics2D g2, int width, int height, int rowIndex, int colIndex,
			int count) {
		Font font = g2.getFont();
		Dimension size = getGridSize(width, height);
		FontMetrics metrics = g2.getFontMetrics(font);
		int w = metrics.stringWidth(Integer.toString(count));
		int h = metrics.getHeight();
		int x = (size.width - w)/2 + colIndex * size.width;
		int y = (rowIndex + 1)* size.height - (size.height - h)/2;
		
		g2.setFont(font);
		g2.setColor(getNumColor(count));
		g2.drawString(Integer.toString(count), x, y);
	}

	private Color getNumColor(int count) {
		switch(count){
		case 1:
			return Color.BLUE;
			
		case 2:
			return Color.GREEN;
			
		case 3:
			return Color.RED;
			
		case 4:
			return Color.BLACK;
			
		default:
			return Color.GRAY;
		}
	}

	private void drawBackground(Graphics2D g2, int width, int height, int y,
			int x) {
		Dimension gridSize = getGridSize(width, height);
		Stroke stroke = new BasicStroke(DEFAULT_LINE_WIDTH);
		g2.setStroke(stroke);
		g2.setColor(BORDER_COLOR);
		
		g2.drawRect(x * gridSize.width, y * gridSize.height, gridSize.width, gridSize.height);
	}

	private void drawMine(Graphics2D g2, int width, int height, int y, int x) throws IOException {
		Dimension size = getGridSize(width, height);
		int x1 = x * size.width;
		int y1 = y * size.height;
		
		Image image = ImageManager.getImage(MINE_IMAGE_FILE_NAME, FileSource.FILE_SYSTEM);
		g2.drawImage(image, x1, y1, size.width, size.height, null);
	}

	private Dimension getGridSize(int width, int height) {
		int w = width / game.getColCount();
		int h = height / game.getRowCount();
		return new Dimension(w, h);
	}

	@Override
	public int getFrameCount() {
		return 0;
	}

	public Game getGame() {
		return game;
	}

	@Override
	public void onStateChanged(int state) {
		this.state = state;
		this.secondsLeft = SECONDS_FOR_SHOWING_MESSAGE;
	}

	public void setMouseGrid(int rowIndex, int colIndex) {
		currentRow = rowIndex;
		currentCol = colIndex;
	}
}
